// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#pragma once

#include <memory>
#include <string>
#include <vector>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/bybit_futures/api_util/auth_key.h"
#include "coin2/exchange/order/bybit.pb.h"

class BybitRateTracker;

class BybitFuturesNativePrivateClient : public coin2::exchange::base::order::NativePrivateClient {
 public:
  using RestParams = coin2::exchange::order::BybitRestParams;
  using NativeClientConfig = coin2::exchange::order::OrderConnectionConfig;
  using ActionType = coin2::exchange::base::order::NativePrivateClient::ActionType;

 public:
  std::shared_ptr<AsioHttpContext> SubmitOrderExecution(const OrderExecutionProto& order);
  std::shared_ptr<AsioHttpContext> SubmitRestQuery(const RestQueryProto& query);

 public:
  explicit BybitFuturesNativePrivateClient(
      const MarketExchangeApi& mea,
      const NativeClientConfig& config,
      bool is_linear);

  std::shared_ptr<AsioHttpContext> QueryBalance();
  std::shared_ptr<AsioHttpContext> QueryPosition(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryFills(const RestParams& params);
  std::shared_ptr<AsioHttpContext> PlaceOrder(
      const RestParams& params,
      const OrderSpec& order_spec);
  std::shared_ptr<AsioHttpContext> AmendOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> CancelSingleOrder(const RestParams& params);

  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) override;

  RestParams GetRestOrderParams(const OrderSpec& order_spec, int64_t proc_order_id);
  RestParams GetRestCancelParams(const IOrderContext& order_context);

  const std::string& GetEndpointGroupQueryAccount() const { return endpoint_group_query_account_; }
  const std::string& GetEndpointGroupQueryOrder() const { return endpoint_group_query_order_; }
  const std::string& GetEndpointGroupQueryTrade() const { return endpoint_group_query_trade_; }
  const std::string& GetEndpointGroupTradeOrder() const { return endpoint_group_trade_order_; }

  bool HasEnoughRateLimit(
      int64_t ts,
      ActionType action_type,
      const std::string& symbol,
      const std::string& endpoint) const;
  void Push(
      int32_t num_reqs,
      int64_t ts,
      ActionType action_type,
      const std::string& symbol,
      const std::string& path);

  void SetMakerOrder(bool is_maker_order);

 private:
  inline bool IsDeliveryNativeSymbol(const std::string& native_symbol) {
    const auto* product = symcache_->GetProductByNative(native_symbol);
    if (!product) {
      // shouldn't reach here
      return false;
    }
    const auto& norm_symbol = product->absolute_norm();
    return norm_symbol.find("PERPETUAL") == std::string::npos;
  }

 private:
  bool is_linear_;
  BybitRateTracker* local_rate_tracker_;

  // group: endpoint_group_query_account_
  // 1.query balance
  // 2.query position
  const std::string endpoint_group_query_account_ = "group_query_account";
  // group: endpoint_group_query_order_
  // 1.query orders
  const std::string endpoint_group_query_order_ = "group_query_order";
  // group: endpoint_group_query_trade_
  // 1.query fills
  const std::string endpoint_group_query_trade_ = "group_query_trade";
  // group: endpoint_group_trade_order_
  // 1.place order
  // 2.amend order
  // 3.cancel order
  const std::string endpoint_group_trade_order_ = "group_trade_order";
};
